package com.pig4cloud.pigx.contract.executer.order.initializer.impl;

import com.pig4cloud.pigx.common.customize.enums.CommonDictEnum;
import com.pig4cloud.pigx.common.customize.i18n.util.MessageUtils;
import com.pig4cloud.pigx.common.customize.mysql.utils.MysqlUtil;
import com.pig4cloud.pigx.common.customize.security.utils.SecurityUtil;
import com.pig4cloud.pigx.common.customize.utils.CommonUtil;
import com.pig4cloud.pigx.contract.bo.ContractOrderNewBO;
import com.pig4cloud.pigx.contract.constant.I18nMessages;
import com.pig4cloud.pigx.contract.enums.ContractOrderEnum;
import com.pig4cloud.pigx.contract.executer.order.initializer.OrderInitializerManager;
import com.pig4cloud.pigx.contract.executer.order.supporter.OrderCalculator;
import com.pig4cloud.pigx.contract.mapper.ContractOrderMapper;
import com.pig4cloud.pigx.contract.mapper.ContractPositionMapper;
import com.pig4cloud.pigx.contract.mongo.entity.ContractSymbolMongo;
import com.pig4cloud.pigx.contract.utils.ContractUtils;
import com.pig4cloud.pigx.contract.vo.ContractOrderInitResVO;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Objects;

/**
 * 限价单订单初始化器
 *
 * @since 2022/8/17 14:25
 */
@Component
public class LimitOrderInitializer extends AbstractOrderInitializer
        implements InitializingBean {

    protected final OrderInitializerManager orderInitializerManager;

    /**
     * 有参构造函数
     * <p>同时给父级对象赋值
     *
     * @since 2022/8/17 20:51
     */
    public LimitOrderInitializer(ContractOrderMapper contractOrderMapper,
                                 ContractPositionMapper contractPositionMapper,
                                 MongoTemplate mongo,
                                 AmqpTemplate rabbit,
                                 CommonUtil commonUtil,
                                 MysqlUtil mysqlUtil,
                                 SecurityUtil securityUtil,
                                 ContractUtils contractUtils,
                                 OrderInitializerManager orderInitializerManager) {
        super(contractOrderMapper, contractPositionMapper, mongo, rabbit, commonUtil, mysqlUtil, securityUtil, contractUtils);
        this.orderInitializerManager = orderInitializerManager;
    }

    /**
     * 当前对象创建后
     *
     * @since 2022/8/17 14:36
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        // 注册到manager
        orderInitializerManager.getInitializerList().add(this);
    }

    /**
     * 判断是否支持
     *
     * @param bo 入参
     * @return {@link boolean}
     * @since 2022/8/17 11:20
     */
    @Override
    public boolean support(ContractOrderNewBO bo) {
        // 不是机器人，是限价单
        return !Objects.equals(CommonDictEnum.YesOrNo.YES.getValue(), bo.getIsRobot())
                && Objects.equals(ContractOrderEnum.Type.LIMIT.getValue(), bo.getType());
    }

    /**
     * 初始化数据
     *
     * @param bo bo
     * @since 2022/8/16 22:22
     */
    @Override
    protected void initParam(ContractOrderNewBO bo) {
        ContractSymbolMongo symbol = bo.getSymbol();

        // 手续费率
        bo.setHandlingFeeRate(symbol.getLimitFeeRate());

        super.initParam(bo);
    }

    /**
     * 校验bo
     *
     * @param bo bo
     * @since 2022/8/16 18:16
     */
    @Override
    protected void validParam(ContractOrderNewBO bo) {
        if (Objects.isNull(bo.getPrice())) {
            throw new RuntimeException(MessageUtils.get(I18nMessages.PRICE_CANNOT_BE_NULL));
        }
        if (bo.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
            throw new RuntimeException(MessageUtils.get(I18nMessages.PRICE_CANNOT_BE_LESS_THAN_OR_EQUAL_TO_ZERO));
        }
        super.validParam(bo);
    }

    /**
     * 校验币对信息
     *
     * @param bo bo
     * @since 2022/8/16 21:05
     */
    @Override
    protected void validSymbol(ContractOrderNewBO bo) {
        super.validSymbol(bo);
        ContractSymbolMongo symbol = bo.getSymbol();

        // 最大挂单数量
        Object pendingOrderCount = contractUtils.incrOrderPending(bo.getUserId(), 1);
        // 记录增加操作，以便下单失败后回滚
        bo.setHasAddPendingNum(true);
        if (!Objects.isNull(pendingOrderCount) && (long) pendingOrderCount > symbol.getMaxPendingOrderNum()) {
            throw new RuntimeException(MessageUtils.get(I18nMessages.MAXIMUM_NUMBER_OF_ORDERS_IS, symbol.getMaxPendingOrderNum()));
        }

        // 如果是条件挂单
        if (bo.getIsConditionPending()) {
            // 最大条件单挂单数量
            Object conditionPendingOrderCount = contractUtils.incrOrderConditionPending(bo.getUserId(), 1);
            // 记录增加操作，以便下单失败后回滚
            bo.setHasAddConditionPendingNum(true);
            if (!Objects.isNull(conditionPendingOrderCount) && (long) conditionPendingOrderCount > symbol.getMaxConditionPendingOrderNum()) {
                throw new RuntimeException(MessageUtils.get(I18nMessages.MAXIMUM_NUMBER_OF_LISTED_ORDERS_IS, symbol.getMaxConditionPendingOrderNum()));
            }
        }

        // 最小下单价格
        if (symbol.getMinOrderPrice().compareTo(bo.getPrice()) > 0) {
            throw new RuntimeException(MessageUtils.get(I18nMessages.MINIMUM_ORDER_PRICE_IS, symbol.getMinOrderPrice()));
        }

        // 限价单单笔最大数量
        if (symbol.getMaxLimitOrderNum().compareTo(bo.getNum()) < 0) {
            throw new RuntimeException(MessageUtils.get(I18nMessages.LIMIT_THE_MAXIMUM_NUMBER_OF_SINGLE_PENS_TO, symbol.getMaxLimitOrderNum()));
        }

        // 限价单价格上限比率。根据标记价求出上限价格
        BigDecimal capPrice = OrderCalculator.getLimitPriceCap(symbol.getLimitOrderPriceCapRatio(), symbol.getMarkPrice());
        if (capPrice.compareTo(bo.getPrice()) < 0) {
            throw new RuntimeException(MessageUtils.get(I18nMessages.LIMIT_ORDER_IS_TOO_HIGH));
        }

        // 限价单价格下限比率。根据标记价求出下限价格
        BigDecimal floorPrice = OrderCalculator.getLimitPriceFloor(symbol.getLimitOrderPriceFloorRatio(), symbol.getMarkPrice());
        if (floorPrice.compareTo(bo.getPrice()) > 0) {
            throw new RuntimeException(MessageUtils.get(I18nMessages.LIMIT_ORDER_IS_TOO_LOW));
        }
    }

    /**
     * 初始化成功
     *
     * @param bo 入参
     * @return {@link ContractOrderInitResVO}
     * @since 2022/8/17 11:31
     */
    @Override
    public ContractOrderInitResVO success(ContractOrderNewBO bo) {
        ContractOrderInitResVO res = super.success(bo);
        // 发送订单延迟过期消息
        contractUtils.sendLimitOrderExpire(bo.getId(), bo.getUserId());

        return res;
    }
}
